<template>
  <div class="login">
    <div class="login-container">
      <h3 class="title">{{ config.site.title }}</h3>
      <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" @keydown="handleKeydown">
        <el-form-item prop="username">
          <el-input v-model="ruleForm.username" placeholder="用户名" size="large" :prefix-icon="User" />
        </el-form-item>
        <el-form-item prop="password">
          <el-input v-model="ruleForm.password" type="password" placeholder="密码" size="large" :prefix-icon="Lock" />
        </el-form-item>
        <el-form-item prop="code" v-if="false">
          <!-- 验证码 no have -->
          <div style="display: flex; width: 100%; overflow: hidden">
            <el-input v-model="ruleForm.code" auto-complete="off" placeholder="验证码" :prefix-icon="CircleCheck" style="width: 60%; margin-right: 12px"> </el-input>
            <div class="login-code">
              <img :src="imgUrl" @click="getCode" class="login-code-img" />
            </div>
          </div>
        </el-form-item>
        <el-form-item>
          <div style="display: flex; width: 100%">
            <el-button type="primary" size="large" :loading="loading" style="width: 60%" @click.native.prevent="submit(ruleFormRef)">登录</el-button>
            <el-button @click="reset(ruleFormRef)" size="large" style="flex: 1">重置</el-button>
          </div>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, reactive, watch, onMounted, toRaw } from 'vue'
import { FormInstance, FormRules, ElMessage } from 'element-plus'
import IUsers from '../interface/IUsers'
import { useRouter } from 'vue-router'
import { User, Lock, CircleCheck } from '@element-plus/icons-vue'
import { useLegalStore, useLegalTypeStore, useLegalCategoryStore, useUsersStore, useTrainingCategoryStore, useProjectssStore, useDeptStore, useTaskTypeStore, useClockinCategoryStore, useProjectCategoryStore, useProjectStatusStore, useHolidayCategoryStore, useAssetCategoryStore, useAssetStatusStore, useLeaveCategoryStore, useOvertimeStatus, useWorkOrderCategoryStore, useWorkOrderStatusStore, useWorkOrderPriorityStore, useWorkOrderSolutionStore, } from '../stores'
import axios from 'axios'
import http from '../http'
import Storage from '../utils/storage'
import { formatDate } from '../utils'
import config from '../config'
import api from '../api'
import.meta.env

type ExtendedIUsers = IUsers & { roleName: string }
const currentUser = ref()
const userlist = ref<ExtendedIUsers[]>([
  { id: 1, username: 'user1', password: '123456', roleName: '制片' },
  { id: 2, username: 'user2', password: '123456', roleName: '组长' },
  { id: 3, username: 'user3', password: '123456', roleName: '组员' },
])
const router = useRouter()
const usersStore = useUsersStore()
const projectssStore = useProjectssStore()
const deptsStore = useDeptStore()
const taskTypeStore = useTaskTypeStore()
const trainingCategoryStore = useTrainingCategoryStore()
const clockinCategoryStore = useClockinCategoryStore()
const projectCategoryStore = useProjectCategoryStore()
const projectStatusStore = useProjectStatusStore()
const holidayCategoryStore = useHolidayCategoryStore()
const assetCategoryStore = useAssetCategoryStore()
const assetStatusStore = useAssetStatusStore()
const leaveCategoryStore = useLeaveCategoryStore()
const legalTypeStore = useLegalTypeStore()
const legalCategoryStore = useLegalCategoryStore()
const ruleFormRef = ref<FormInstance>()
const systemDictList = ref<any>([])

let username = 'admin'
// let password = '123admin'
let password = '123456'
// if (import.meta.env.VITE_APP_ENV === 'development') {
//   // 这里可以继续添加后续基于开发环境下的用户名和密码的业务逻辑
// }
if (import.meta.env.VITE_APP_ENV === 'production') {
  username = ''
  password = ''
  // 这里可以继续添加后续基于生产环境下的用户名和密码的业务逻辑
}

const ruleForm = ref<IUsers>({
  username,
  password,
  code: '',
  uuid: '',
})
const rules = reactive<FormRules<IUsers>>({
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
})
const imgUrl = ref('')
const userInfo = ref({})
const loading = ref(false)

/**
 * 异步获取代码信息
 *
 * @returns 无返回值
 */
const getCode = async () => {
  loading.value = false
  const codeRes = await axios({ method: 'GET', url: '/dev-api/code' })
  const { code, uuid, img } = codeRes.data
  if (code === 200) {
    imgUrl.value = `data:image/gif;base64,${img}`
    ruleForm.value.uuid = uuid
  }
}

onMounted(async () => {
  Storage.clear()
  getCode()
})

/**
 * 键盘按下事件处理函数
 *
 * @param event - 键盘事件对象
 */
const handleKeydown = (event: KeyboardEvent) => {
  // 如果按键是回车键
  if (event.key === 'Enter') {
    // 提交表单
    submit(ruleFormRef.value)
  }
}
watch(
  () => currentUser.value,
  (nv: number) => {
    const item = userlist.value.find((item: IUsers) => item.id === nv)
    if (item) {
      ruleForm.value = item
    }
  }
)

/**
 * 获取项目列表
 *
 * @returns {Promise<void>} 返回Promise对象，无返回值
 */
const getProjectList = async () => {
  const res = await api.Projects.getProjectListAll()
  const { code, rows } = res
  if (code === 200) {
    projectssStore.setAllState(rows)
  }
}

/**
 * 获取部门列表
 *
 * @returns {Promise<void>} 返回Promise对象，无返回值
 */
const getDeptList = async () => {
  const req = await http({
    method: 'GET',
    path: '/dev-api/system/dept/list',
    params: {
      status: 0,
    },
  })
  const { msg, code, data } = req
  if (code == 200) {
    const treeData = convertToTree(data)
    deptsStore.setAllState(treeData)
    deptsStore.setAllListState(data)
  } else {
    ElMessage.error(msg)
  }
}
function convertToTree(data: any) {
  const map: any = {}
  const treeData: any[] = []

  // 首先将数据存储在一个以 deptId 为键的对象中，方便后续查找
  data.forEach((item: any) => {
    map[item.deptId] = item
  })

  data.forEach((item: any) => {
    if (item.parentId === 0) {
      // 如果 parentId 为 0，说明是顶级节点，直接添加到结果数组中
      treeData.push(item)
    } else {
      // 如果不是顶级节点，找到其父节点并将当前节点添加到父节点的 children 数组中
      const parent = map[item.parentId]
      if (parent) {
        parent.children = parent.children || []
        parent.children.push(item)
      }
    }
  })

  return treeData
}

/**
 * 获取用户信息
 *
 * @returns {Promise<void>} 无返回值
 */
const getUserInfo = async () => {
  const res = await http({
    method: 'GET',
    // path: '/dev-api/system/user/list',
    path: '/dev-api/system/user/getInfo',
    // params: { userName: ruleForm.value.username },
  })
  // console.log('res.data:', res.data)
  const { code, user, roles } = res
  if (code == 200) {
    const temp = user
    const deptInfo = { ...temp.dept }
    const rolesTemp = { ...temp.roles }
    userInfo.value = {
      userId: temp.userId,
      nickName: temp.nickName,
      remark: temp.remark,
      phonenumber: temp.phonenumber,
      ...deptInfo,
      ...temp,
      rolesTemp,
      roles,
    }

    // console.log('userInfo:', userInfo.value)
  }
}

/**
 * 获取用户审批列表
 *
 * 使用api.Users.getApprovalAll()方法异步获取用户审批列表，并将结果通过useUsersStore().setUserApprovalList()方法存储。
 */
const getUserApprovalList = async () => {
  const rows = await api.Users.getApprovalAll()
  const rows2 = await api.Users.getApprovalAll(101)
  const rows3 = await api.Users.getAll({ pageSize: 9999 })
  const rows4 = await api.Users.getApprovalAll(108)
  const rows5 = await api.Users.getApprovalAll(109)
  // 主管
  useUsersStore().setUserApprovalList(rows)
  // 总监
  useUsersStore().setUserApprovalList2(rows2)
  // 副总经理
  useUsersStore().setUserApprovalList108(rows4)
  // 总经理
  useUsersStore().setUserApprovalList109(rows5)
  // 所有用户
  useUsersStore().setUserAllList(rows3)
}

/**
 * 获取法律信息
 *
 * @returns {Promise<void>} 无返回值
 */
const getLegalStore = async () => {
  const result = await api.Legal.getLegalAll()
  const legalType = useLegalTypeStore().legalType
  const legalCategory = useLegalCategoryStore().legalCategory

  const newResult = result.map((item: any) => {
    // 关联 legalType
    const matchedLegalType = legalType.find((lt: any) => lt.dictValue === item.legalType.toString())

    // 关联 legalCategory
    const matchedLegalCategory = legalCategory.find((lc: any) => lc.dictValue === item.legalCategory.toString())
    return {
      ...item,
      legalTypeLabel: matchedLegalType ? matchedLegalType.dictLabel : '',
      legalCategoryLabel: matchedLegalCategory ? matchedLegalCategory.dictLabel : '',
    }
  })
  useLegalStore().setAllState(newResult)
}

/**
 * 异步获取系统字典数据列表
 *
 * 此函数通过发送GET请求来获取特定字典类型的数据列表它将字典类型作为参数，
 * 并从服务器响应中解析数据如果服务器返回的状态码为200，则将解析后的数据返回；
 * 否则，返回一个空数组
 *
 * @param dictType 字典类型，用于查询对应的字典数据
 * @returns 返回系统字典数据列表，如果请求失败或状态码不是200，则返回空数组
 */
const getSystemDictDataList = async (dictType: string) => {
  const result = systemDictList.value.filter((item: any) => item.dictType === dictType)
  // console.log('ress:', ress)
  // // 发送GET请求到指定路径，携带字典类型作为查询参数
  // const res = await http({
  //   method: 'GET',
  //   path: '/dev-api/system/dict/data/list',
  //   params: { dictType },
  // })

  // // 初始化结果变量为空数组，用于存放解析后的字典数据
  // let result: any = []
  // // 解构赋值从响应中提取状态码和数据行
  // const { code, rows } = res
  // // 检查响应状态码，如果为200，则将数据行赋值给结果变量
  // if (code === 200) {
  //   result = rows
  // }
  // 返回结果变量
  return result
}

/**
 * 获取所有系统字典数据
 *
 * @returns 返回系统字典数据的数组。如果请求失败或返回的状态码不为200，则返回空数组。
 */
const getSystemDictAll = async () => {
  // 发送GET请求到指定路径，携带字典类型作为查询参数
  const res = await http({
    method: 'GET',
    path: '/dev-api/system/dict/data/list',
    params: {
      pageSize: 9999,
    },
  })

  // 初始化结果变量为空数组，用于存放解析后的字典数据
  let result: any = []
  // 解构赋值从响应中提取状态码和数据行
  const { code, rows } = res
  // 检查响应状态码，如果为200，则将数据行赋值给结果变量
  if (code === 200) {
    result = rows
  }
  // 返回结果变量
  systemDictList.value = result
}

/**
 * 计算工作时长
 *
 * @param startWorkTime 开始工作时间（字符串格式）
 * @param endWorkTime 结束工作时间（字符串格式）
 * @param startLunchTime 午餐开始时间（字符串格式，可选）
 * @param endLunchTime 午餐结束时间（字符串格式，可选）
 * @returns 包含工作时长的小时和分钟的对象
 */
const getHourDiff = (startWorkTime: string, endWorkTime: string, startLunchTime: string | null = null, endLunchTime: string | null = null) => {
  const start = new Date(startWorkTime) as any
  const end = new Date(endWorkTime) as any

  let totalWorkingHours = (end - start) / (1000 * 60 * 60) // 总工作时间（小时）

  // 如果午餐时间参数存在，则扣除午餐时间
  if (startLunchTime && endLunchTime) {
    const lunchStart = new Date(startLunchTime) as any
    const lunchEnd = new Date(endLunchTime) as any
    let lunchBreakHours = (lunchEnd - lunchStart) / (1000 * 60 * 60) // 午餐时间（小时）
    totalWorkingHours -= lunchBreakHours
  }
  // 根据传入的格式参数返回不同的格式
  const hours = Math.floor(totalWorkingHours)
  const minutes = Math.round((totalWorkingHours - hours) * 60)

  const result = {
    minutes: hours * 60 + minutes,
    hour: totalWorkingHours.toFixed(2),
    text: `${hours} 小时 ${minutes} 分钟`,
  }
  return result
}

/**
 * 统一初始化所有应用数据
 * 整合所有分散的数据获取调用
 */
const initAllData = async () => {
  // 并行执行不依赖其他数据的初始化任务
  const independentTasks = [getSystemDictAll(), getUserInfo(), getProjectList(), getDeptList()]

  // 等待基础数据加载完成
  await Promise.all(independentTasks)

  // 依赖systemDict数据的初始化任务
  const dictDependentTasks = [
    initSystemDictData(), // 使用之前建议的统一字典初始化函数
    getLegalStore(),
    getUserApprovalList(),
  ]

  await Promise.all(dictDependentTasks)
}

/**
 * 统一初始化系统字典数据
 */
const initSystemDictData = async () => {
  const dictConfigs = [
    { type: 'training_category', store: trainingCategoryStore },
    { type: 'timelog_category', store: taskTypeStore },
    { type: 'clockin_category', store: clockinCategoryStore },
    { type: 'overtime_status', store: useOvertimeStatus() },
    { type: 'project_category', store: projectCategoryStore },
    { type: 'project_status', store: projectStatusStore },
    { type: 'asset_category', store: assetCategoryStore },
    { type: 'asset_status', store: assetStatusStore },
    { type: 'leave_status', store: leaveCategoryStore },
    { type: 'legal_type', store: legalTypeStore },
    { type: 'legal_category', store: legalCategoryStore },
    { type: 'holiday_category', store: holidayCategoryStore },
    { type: 'wo_category', store: useWorkOrderCategoryStore() },
    { type: 'wo_status', store: useWorkOrderStatusStore() },
    { type: 'wo_priority', store: useWorkOrderPriorityStore() },
    { type: 'wo_solution', store: useWorkOrderSolutionStore() },
  ]

  const promises = dictConfigs.map(async (config) => {
    try {
      const result = await getSystemDictDataList(config.type)
      config.store.setAllState(result) // 直接调用，保持 this 上下文
    } catch (error) {
      console.error(`Failed to initialize ${config.type}:`, error)
    }
  })

  await Promise.all(promises)
}
/**
 * 提交表单函数
 *
 * @param formEl 表单实例，类型为FormInstance或undefined
 * @returns 无返回值
 */
const submit = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate(async (valid) => {
    loading.value = true
    if (valid) {
      const res = await axios({
        method: 'POST',
        url: '/dev-api/auth/login',
        headers: {
          isToken: false,
        },
        data: ruleForm.value,
      })
      const { data, code, msg } = res.data
      if (code === 200) {
        // console.log('200', 200)
        usersStore.setAccessToken(data.access_token)

        await initAllData()

        const { nickName, startWorkTime, endWorkTime, startLunchTime, endLunchTime, startOvertimeTime, city, roles, deptId } = userInfo.value as any

        const doDay = formatDate(new Date(), 'yyyy-MM-dd')
        const hourDiff = getHourDiff(doDay + ' ' + startWorkTime, doDay + ' ' + endWorkTime, doDay + ' ' + startLunchTime, doDay + ' ' + endLunchTime)
        const { username, code, uuid, password } = { ...toRaw(ruleForm.value) }
        const isChangChun: boolean = startWorkTime == '08:00' // 判断工作地点是否是长春
        let identityName = ''
        if (roles.includes('zongjingli')) {
          identityName = '总经理' //
        } else if (roles.includes('fuzongjingli')) {
          identityName = '副总经理' //
        } else if (roles.includes('daoyan')) {
          identityName = '导演' //
        } else if (roles.includes('zhipian')) {
          identityName = '制片' //
        } else if (roles.includes('zhuguan')) {
          identityName = '主管' //
        } else if (roles.includes('zongjian')) {
          identityName = '总监' //
        } else if (roles.includes('xingzheng')) {
          identityName = '行政' //
        } else if (roles.includes('yuangong')) {
          identityName = '普通员工' //
          if (deptId == '108') {
            identityName = '北京动画组' // 北京动画组
          } else if (deptId == '226') {
            identityName = '长春动画组' // 长春动画组
          }
        } else {
          identityName = '其他' // 其他身份
        }
        usersStore.setAllState({ nickName, identityName, code, uuid, ...toRaw(userInfo.value), password, username, token: data.access_token, ...hourDiff, startWorkTime, endWorkTime, isChangChun, startOvertimeTime, city })

        ElMessage({
          showClose: true,
          message: '登录成功',
          type: 'success',
          duration: 2000,
        })
        setTimeout(() => {
          // router.push({ name: 'Home' })
          router.push({ name: 'QuickNavigation' })
        }, 1000)
        loading.value = false
      } else {
        loading.value = false
        ElMessage({
          showClose: true,
          message: msg,
          type: 'error',
        })
        getCode()
      }
    } else {
      loading.value = false
    }
  })
}
const reset = (formEl: FormInstance | undefined) => {
  loading.value = false
  if (!formEl) return
  formEl.resetFields()
}
</script>
<style lang="scss">
.login {
  margin: 0 auto;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-image: url('../assets/imgs/login-background.jpg');
  background-size: cover;
  .login-container {
    border-radius: 6px;
    background: #ffffff;
    width: 400px;
    padding: 25px 30px 5px 25px;

    .title {
      margin: 0px auto 30px auto;
      text-align: center;
      color: #707070;
    }
    .el-input {
      height: 38px;
      input {
        height: 38px;
      }
    }
    .input-icon {
      height: 39px;
      width: 14px;
      margin-left: 2px;
    }
    .login-code {
      height: 38px;
      float: right;
      img {
        cursor: pointer;
        vertical-align: middle;
      }
    }
    .login-code-img {
      height: 38px;
      width: 126px;
    }
  }
}
</style>
